package com.jxy.bean.constant;

import com.jxy.bean.ClassFile;
import com.jxy.tool.Tool;

import java.io.DataInputStream;

public class MethodHandleInfo extends ConstantPool {
    public int reference_kind;
    public int reference_index;

    public MethodHandleInfo(DataInputStream dis, ClassFile cf) {
        super(ConstantPoolTag.CONSTANT_MethodHandle.getTag(), cf);
        //长度u2
        reference_kind = Tool.readU1(dis);
        reference_index = Tool.readU2(dis);
    }

    public String getReference() {
        if (valid()) {
            if (cf.getPools()[reference_index] instanceof FieldrefInfo) {
                FieldrefInfo fieldrefInfo = (FieldrefInfo) cf.getPools()[reference_index];
                return fieldrefInfo.getClassName() + " " + fieldrefInfo.getNameAndType();
            }
            if (cf.getPools()[reference_index] instanceof MethodrefInfo) {
                MethodrefInfo methodrefInfo = (MethodrefInfo) cf.getPools()[reference_index];
                return methodrefInfo.getClassName() + " " + methodrefInfo.getNameAndType();
            }
            if (cf.getPools()[reference_index] instanceof InterfaceMethodrefInfo) {
                InterfaceMethodrefInfo interfaceMethodrefInfo = (InterfaceMethodrefInfo) cf.getPools()[reference_index];
                return interfaceMethodrefInfo.getClassName() + " " + interfaceMethodrefInfo.getNameAndType();
            }

        }
        return "reference_index err !";
    }

    @Override
    public String toString() {
        return ConstantPoolTag.CONSTANT_MethodHandle.getType() + "{tag:" + tag + ", reference_kind:" + reference_kind + ", reference_index:" + reference_index + "(" + getReference() + ")}";
    }

    @Override
    public boolean valid() {
        //reference_kind值必须在1-9之间，reference_index指向结构，暂不校验指向结构的名字是否<init> or <clinit> 等。
        if (reference_kind >= 1 && reference_kind <= 9) {
            switch (reference_kind) {
                case 1://REF_getField
                case 2://REF_getStatic
                case 3://REF_putField
                case 4://REF_putStatic
                    //reference_kind为1-4，reference_index必须指向CONSTANT_Fieldref结构
                    if (cf.getPools()[reference_index].getTag() == ConstantPoolTag.CONSTANT_Fieldref.getTag()) {
                        return true;
                    }
                case 5://REF_invokeVirtual
                case 8://REF_newInvokeSpecial
                    //reference_kind为5或8，reference_index必须指向CONSTANT_Methodref_info结构
                    if (cf.getPools()[reference_index].getTag() == ConstantPoolTag.CONSTANT_Methodref.getTag()) {
                        return true;
                    }
                case 6://REF_invokeStatic
                case 7://REF_invokeSpecial
                    //reference_kind为6或7，reference_index必须指向CONSTANT_Methodref结构(52.0版本以下)，reference_index必须指向CONSTANT_Methodref_info结构或者CONSTANT_InterfaceMethodref_info结构(包含52.0版本及以上)
                    if (cf.getPools()[reference_index].getTag() == ConstantPoolTag.CONSTANT_Methodref.getTag() || cf.getPools()[reference_index].getTag() == ConstantPoolTag.CONSTANT_InterfaceMethodref.getTag()) {
                        return true;//此处暂不检验版本
                    }
                case 9://REF_invokeInterface
                    //reference_kind为9，reference_index必须指向CONSTANT_InterfaceMethodref_info结构
                    if (cf.getPools()[reference_index].getTag() == ConstantPoolTag.CONSTANT_InterfaceMethodref.getTag()) {
                        return true;
                    }
                default:
                    //不会出错，上面已经有if判断了
                    break;
            }
        }
        return false;
    }
}
